package com.wmz.filter;

import com.alibaba.fastjson.JSON;
import com.wmz.constant.AuthConstants;
import com.wmz.model.SecurityUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author wmz
 * @date 2024/7/6 16:21
 * @description token解析过滤器
 */
@Component
public class TokenTranslationFilter extends OncePerRequestFilter {
    @Autowired
    private StringRedisTemplate redisTemplate;
    /**
     * token解析过滤器
     *  只处理携带token的请求，将用户信息转换过来
     *  未携带token的请求，交给security处理，如果放行直接访问。
     *  如果没有放行，则交给security的AuthenticationEntrypoint处理
     *      1.获取token
     *      2.如果有，token转换并处理token续约
     *      3.存放到security上下文中
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取请求信息
        String authorization = request.getHeader(AuthConstants.AUTHORIZATION);
        //判断是否有值
        if(StringUtils.hasText(authorization)) {
            //token存在
            String token = authorization.replaceFirst(AuthConstants.BEARER, "");
            //token是否存在
            if(StringUtils.hasText(token)){
                //解决token续签
                Long tokenExpire = redisTemplate.getExpire(AuthConstants.LOGIN_TOKEN_PREFIX + token, TimeUnit.SECONDS);
                //判断是否小于阈值
                if(tokenExpire < AuthConstants.TOKEN_EXPIRE_THRESHOLD_TIME) {
                    //续签：再续4个小时
                    redisTemplate.expire(AuthConstants.LOGIN_TOKEN_PREFIX + token, Duration.ofSeconds(AuthConstants.TOKEN_TIME));
                }
                //token转换为用户信息
                String userStr = redisTemplate.opsForValue().get(AuthConstants.LOGIN_TOKEN_PREFIX + token);
                SecurityUser securityUser = JSON.parseObject(userStr, SecurityUser.class);
                //处理权限
                Set<SimpleGrantedAuthority> grantedAuthorities = securityUser.getPerms().stream()
                        .map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
                //创建security框架认识的用户对象
                UsernamePasswordAuthenticationToken authenticationToken =
                        new UsernamePasswordAuthenticationToken(securityUser, null, grantedAuthorities);
                //将用户对象放到security上下文中
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        //处理后往下继续执行
        filterChain.doFilter(request,response);
    }
}
